<!DOCTYPE html
    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:py="http://genshi.edgewall.org/"
      xmlns:xi="http://www.w3.org/2001/XInclude">
  <xi:include href="layout.html" />
  <xi:include href="macros.html" />
  <head>
    <title>Release Burndown</title>
    <style>
    table, th, td {
    	font-size: 100%;
    	text-align: center;
    }
    .populate {
    	text-align: left;
    	font-size: 10px;
    }
    .populate input{
    	height: 13px;
    	width: 20px;
    	font-size: 10px;
    }
    table {
    	border: 1px solid #D7D7D7;
    	width: 750px;
    }
    table thead {
    	background: #D7D7D7;
    }
    th {
    	font-weight: bolder;
    }
    .tasks {
    	display:block;
    }
    .addtask {
    	display:none;
    	text-align:left;
    }

    .collapsed {
    	display:table;
    }
	
	.visivel {
		display: block;
	}
	
	.error {
		background-color: #ff7d1d;
		border-color: #000;
	}
	
	select {
		font-size: 10px;
		border:1px solid #D7D7D7;
	}
    </style>
    <!--link rel="stylesheet" href="http://github.com/jquery/qunit/raw/master/qunit/qunit.css" type="text/css" media="screen" /-->
	<!--script type="text/javascript" src="http://github.com/jquery/qunit/raw/master/qunit/qunit.js"></script-->

	<script type="text/javascript">
	//<![CDATA[ 
	jQuery(document).ready(function($) {
		document.getElementById('newReleaseBurndownForm').init_date.value = new Date().toString();
    });
	
	var Debugger = function(level) {
		this.level = level;
		this.debug = function(message) {
			if(level < 1)
				alert(message);
		}
		
		this.trace = function(message) {
			if(level < 2)
				alert(message);
		}
	}
	
	var logger = new Debugger(2);
	
	String.prototype.trim = function() {
		return jQuery.trim(this);
	}
	
	String.prototype.isEmpty = function() {
		return this.trim().length == 0;
	}
	
	String.prototype.isNumeric = function() {
		return this.match(/^\d*$/) != null;
	}
	
	String.prototype.isValidDate = function() {
		pattern = '${date_hint}';
		if(this.length != pattern.length) return false;
		
		year = pattern.match(/Y+/g)[0];
		
		regex = (year.length == 2) ? /^\d{2}\/\d{2}\/\d{2}$/ : /^\d{2}\/\d{2}\/\d{4}$/;

		return this.match(regex) != null;
	}
	
	String.prototype.format = function() {
		var retorno = this;
		for(var i=0; i < arguments.length; i++) {
			retorno = retorno.replace(/%s/, arguments[i]);
		}
		
		return retorno;
	}
	
	String.prototype.right = function(length) {
		if(this.length <= length) return this;
		
		return this.substring(this.length - length, this.length);
	}
	
	Date.prototype.clone = function () {
		return new Date(this.getTime());
	}
	
	Date.prototype.toString = function () {
		var dia = "00" + this.getDate();
		var mes = "00" + (this.getMonth() + 1);
		var ano = this.getFullYear();
		
		pattern = '${date_hint}';
		
		switch(pattern)	{
			case 'DD/MM/YYYY':
				return "%s/%s/%s".format(dia.right(2), mes.right(2), ano);
			case 'MM/DD/YY':
				return "%s/%s/%s".format(mes.right(2), dia.right(2), ("" + ano).right(2));
			case 'MM/DD/YYYY':
				return "%s/%s/%s".format(mes.right(2), dia.right(2), ("" + ano).right(2));
		}
			
		return "%s/%s/%s".format(dia.right(2), mes.right(2), ano);
	}
	
	function addError(element, message, errors, firstError) {
		var inputMsgHolder = null;
		var name = element.name;
		
		if(!firstError.error)
			firstError['error'] = element;
		
		logger.debug("Add error for %s".format(name));
		errors[name] = message;
		element.className = 'error';
			
		element.setAttribute("valid", false);
	}
	
	function showErrors(errors) {
		var text = "";
		
		for(prop in errors) {
			text += errors[prop] + "\n";
		}
		
		alert(text);
	}
	
	function removeError(element) {
		var inputMsgHolder = null;
		var name = element.name;
		
		logger.debug("Remove error for %s".format(name));
		
		element.className = '';
		element.setAttribute("valid", true);
		
		logger.debug("Remove error for %s - END".format(name));
	}
	
	function validate(form) {
		var el = null;
		var isRequired = false;
		var value = null;
		var name = null;
		
		var label = null;
		var allow = true;
		var firstErrorElement = null;
		var datatype = null;
		var errors = {};
		var firstError = {};
		
		try {
			for(var i = 0; i < form.elements.length; i++) {
				el = form.elements[i];
				removeError(el);
				
				isRequired = el.getAttribute("required");
				label = el.getAttribute("label");
				datatype = el.getAttribute("datatype");
				value = el.value;
				name = el.name;
				
				logger.debug("Validating field %s".format(name));

				label = (label == null || label.isEmpty()) ? name : label;
				
				if(isRequired && value.isEmpty()) {
					addError(el, 'Field "' + label + '" required', errors, firstError);
					allow = false;
				}
				
				logger.debug("The value of attribute \"Valid\" is %s for field %s".format(el.getAttribute("valid"), name));
				if(!eval(el.getAttribute("valid"))) 
					continue;
				
				logger.trace("Datatype for field %s is %s".format(name, datatype));
				if(datatype != null && !datatype.isEmpty() && !value.isEmpty()) {
					switch(datatype) {
						case 'integer':
							if(!value.isNumeric()) {
								addError(el, 'Field "' + label + '" accepts only numbers', errors, firstError);
								allow = false;
							}
						break;
						case 'date':
							if(!value.isValidDate()) {
								addError(el, 'Field "' + label + '" accepts a date (dd/mm/yyyy)', errors, firstError);
								allow = false;
							}
						break;
					}
				}
			}
		} catch (_ex) {
			alert(_ex.message);
			allow = false;
		}
		
		if(!allow) {
			showErrors(errors);
			firstError.error.focus();
		}
			
		return allow;
	}
	
	function parseDate(strData) {
		pattern = '${date_hint}';
		
		if(strData.length != pattern.length)
			throw new Error("Unparseable date. Pattern is %s".format(pattern));
		
		dayIndex = pattern .indexOf('DD');
		monthIndex = pattern .indexOf('MM');
		yearIndex = pattern .indexOf('YY');
		yearLength = pattern .match(/Y+/)[0].length;
		
		dia = strData.substring(dayIndex, dayIndex+2).replace(/^0*/,'');
		mes = strData.substring(monthIndex, monthIndex+2).replace(/^0*/,'') - 1;
		ano = strData.substring(yearIndex, yearIndex+yearLength).replace(/^0*/,'');
		
		if(ano.length == 2) ano = '20' + ano;

		return new Date(ano, mes, dia, 0, 0, 0, 0);
	}

	function formatDate(date) {
		return date.getDate() + "/" + (date.getMonth() + 1);
	}
	
	function addDays(date, dias) {
		DAY = 24 * 60 * 60 * 1000;

		clone = new Date(date.getTime() + (dias * DAY));
		
		return clone;
	}
	
	function addWorkingDays(date, dias) {
		remaining = dias;
		retorno = date.clone();
		
		while(remaining > 0) {
			retorno = addDays(retorno, 1);
			
			switch(retorno.getDay()) {
				case 0:
				case 6:
				break;
				default:
					remaining--;
			}
		}
		
		return retorno;
	}
	
	function excludeRelease(form) {
		if(!confirm("Are you sure you want to exclude this Release Burndown Chart?")) return;
		
		form.act.value = 'remove_release'
		form.submit();
	}
	
    function createGraphics(form) {
        var releaseName = form.release_name.value;
        var velocity = parseInt(form.velocity.value);
        var points = form.points.value;
        var initDate = form.init_date.value;
        var daysSprint = parseInt(form.working_days.value);
		var releaseId = parseInt(form.id.value);

		var data = [];
		var remainingPoints = parseInt(points);
		var lastDate = parseDate(initDate);
		var sprintVelocity = 0;
		
		data.push({points:remainingPoints, date: lastDate, added_points: 0, removed_points: 0});
		
		jQuery(form).find('input').filter(function(indice){
			return this.name == 'sprint';
		}).each(function(indice){
			sprint = eval("o=" + this.value);
			
			sprintVelocity = parseInt(sprint.points);
			sprintAddedPoints = parseInt(sprint.added_points);
			sprintRemovedPoints = parseInt(sprint.removed_points);
			remainingPoints -= sprintVelocity;
			
			lastDate = parseDate(sprint.due_date);
			
			
			remainingPoints -= sprintRemovedPoints;
			remainingPoints += sprintAddedPoints;
			data.push({points:remainingPoints, date:lastDate, added_points: sprintAddedPoints, removed_points: sprint.removed_points});
		});

		logger.trace("real data is: %s".format(data));
		while(remainingPoints > 0) {
			remainingPoints -= velocity;
			remainingPoints =  (remainingPoints < 0) ? 0:remainingPoints;
			lastDate = addWorkingDays(lastDate, daysSprint);
			data.push({points:remainingPoints, date: lastDate, added_points: 0, removed_points: 0});
		}
		
		var img = document.getElementById("img_release" + releaseId);

		var originalPoints = "";
		var addedPoints = "";
		var removedPoints = "";
		var donePoints = "";
		var dateLabels = "";
		
		var width = 700;
		//var columnWidth = 80;
		var maxSize = points;
		
		for(i = 0; i < data.length; i++) {
			originalPoints += (data[i].points - data[i].added_points);
			addedPoints += data[i].added_points;
			removedPoints += data[i].removed_points;
			donePoints += (data[i].points);
			dateLabels += formatDate(data[i].date);
			
			maxSize = Math.max(maxSize, data[i].points + data[i].added_points);
			
			//width += columnWidth;
			if(i < data.length - 1) {
				originalPoints += ",";
				addedPoints += ",";
				donePoints += ",";
				removedPoints += ",";
				dateLabels += "|";
			}
		}
		
		//width = Math.min(750, width);

		var step = 10;
		
		if(maxSize > 400) {
			step = 50;
		} else if(maxSize > 200) {
			step = 40;
		} else if(maxSize > 100) {
			step = 20;
		}
		
		var lineWidth = 1;
		var fontSize = 10;
		var barWidth = 35;
		var addPointsColor = 'ffd200';
		var barColor = 'fdfb65';
		var removedColor = '2cc5fe';
		var pointSize = 3;
		var barSpacing = 4;
		
		var estimatedWidth = (barWidth * data.length) + (barSpacing * (data.length - 1));
		
		var offset = 0;
		if(estimatedWidth < width) {
			offset = width - estimatedWidth;
			
			barSpacing += parseInt(offset / (data.length - 1));
		} else if(estimatedWidth > width) {
			barSpacing = 2;
			estimatedWidth -= (barSpacing * (data.length - 1));
			
			offset = estimatedWidth - width;
			barWidth -= parseInt(offset/data.length);
			
			barWidth = barWidth < 10 ? 10 : barWidth;
		}
		
		width += 50;
		
		var url = "http://chart.apis.google.com/chart?cht=bvs&chs=" + width + "x300&chco=" + barColor + "," + addPointsColor + "," + removedColor + "&";
		url += "chd=t3:" + originalPoints + "|" + addedPoints + "|" + removedPoints + "|" + donePoints;
		url += "&chxt=y,x,r,t&chxl=";
		url += "1:|" + dateLabels;
		url += "|2:||3:|"
		url += "&chg=0,10,1,0,10"; //Line Grid - <x_axis_step_size>,<y_axis_step_size>,<dash_length>,<space_length>,<x_offset>,<y_offset>
		url += "&chxr=0,0," + maxSize + "," + step + "&chbh=" + barWidth + "," + barSpacing + "&chtt=Release Burndown&chds=0," + maxSize + "&chdl=Original|Adicionado|Removido&chdlp=b&chm=D,cc0000,3,0," + lineWidth + "|N,FF0000,-1,-1," + fontSize;
		url += "|o,cc0000,3,," + pointSize + "|N,FF0000,-1,-1,10";
		img.src = url;
		
		img.style.display = 'block';
    }
	
	function newRelease(action) {
		container 	= document.getElementById('releaseNewForm');
		botao 		= document.getElementById('releaseNewButton');
		
		container.style.display = action == 'open' ? 'block':'none';
		botao.style.display 	= action == 'open' ? 'none':'block';
	}
	
	function clearForm(form) {
		var el = null;
		for(var i = 0; i < form.elements.length; i++) {
			el = form.elements[i];
			
			if (el.type == 'text') {
				el.value = '';
			}
		}
	}

	// Sprint Functions ==========================================
	var Sprint = {
		showForm: function(form) {
			var releaseId = form.id.value;
			
			working_days = form.working_days.value;
			points = form.velocity.value;
			
			if(form.due_date.value.isEmpty() && !working_days.isEmpty() && working_days.isNumeric())
				form.due_date.value = addWorkingDays(this.lastDate(form), working_days);
				
			if(form.sprint_points.value.isEmpty() && !points.isEmpty() && points.isNumeric())
				form.sprint_points.value = points;
			
			jQuery("#sprintForm%s".format(releaseId)).show();
			jQuery("#newFormLink%s".format(releaseId)).hide();
		},
		cancel: function(form) {
			var releaseId = form.id.value;
			
			form.act.value = 'edit';
			form.sprint_id.value = '';
			form.due_date.value = '';
			form.sprint_points.value = '';
			form.added_points.value = '0';
			form.removed_points.value = '0';
			
			jQuery("#sprintForm%s".format(releaseId)).hide();
			jQuery("#newFormLink%s".format(releaseId)).show();
		},
		edit: function(form, data) {
			this.showForm(form);
			
			form.sprint_id.value = data.id;
			form.due_date.value = data.due_date;
			form.sprint_points.value = data.points;
			form.added_points.value = data.added_points;
			form.removed_points.value = data.removed_points;
		},
		remove: function(form, sprint_id) {
			if(!confirm('Are you sure you want to remove this Sprint Result?')) return;
			
			form.act.value = 'remove_sprint'
			form.sprint_id.value = sprint_id;
			form.submit();
		},
		showResults: function(releaseId) {
			jQuery('#sprints%s'.format(releaseId)).toggleClass('addtask');
		},
		lastDate: function(form) {
			var last = form.init_date.value;
			
			jQuery(form).find('input').filter(function(indice){
				return this.name == 'sprint';
			}).each(function(indice){
				sprint = eval("o=" + this.value);
				
				last = sprint.due_date;
			});
			
			if(last.isEmpty())
				return "";
			else
				return parseDate(last);
		},
		save: function (form) {
		
			form.act.value = form.sprint_id.value.isEmpty() ? 'add_sprint' : 'edit_sprint';
			
			try {
				var errors = {}
				var firstError = {}
				var dueDate = form.due_date.value;
				var sprintPoints = form.sprint_points.value;
				var addedPoints = form.added_points.value;
				var removedPoints = form.removed_points.value;
				
				if(dueDate.isEmpty()) {
					addError(form.due_date, "Field \"End date\" is required", errors, firstError)
				} else {
					if(!dueDate.isValidDate()) {
						addError(form.due_date, "Field \"End date\" must be a valid date", errors, firstError);
					} else {
						if(parseDate(dueDate).getTime() < parseDate(form.init_date.value).getTime())
							addError(form.due_date, "Field \"End date\" must be later than Release Start Date", errors, firstError)
					}
				}
				
				if(sprintPoints.isEmpty()) {
					addError(form.sprint_points, "Field \"Points\" is required", errors, firstError)
				} else {
					if(!sprintPoints.isNumeric()) {
						addError(form.sprint_points, "Field \"Points\" must be a valid number", errors, firstError)
					}
				}
				
				if(addedPoints.isEmpty()) {
					addError(form.added_points, "Field \"Added Points\" is required", errors, firstError)
				} else {
					if(!addedPoints.isNumeric()) {
						addError(form.added_points, "Field \"Added Points\" must be a valid number", errors, firstError)
					}
				}
				
				if(removedPoints.isEmpty()) {
					addError(form.removed_points, "\"Field Removed Points\" is required", errors, firstError)
				} else {
					if(!removedPoints.isNumeric()) {
						addError(form.removed_points, "Field \"Removed Points\" must be a valid number", errors, firstError)
					}
				}
				
				if(!firstError.error)
					form.submit();
				else {
					showErrors(errors);
					firstError.error.focus();
				}
			} catch (_ex) {
				alert("There was an error: %s".format(_ex.message));
				this.cancel();
			}
		}
	};
	//]]>
    </script>
  </head>
  <body py:if="refresh">
	<script>window.location.href='${href.releaseburndown()}'</script>
  </body>
  <body py:if="not refresh">
    <div id="content" class="roadmap">
      <h1>Release Burndown</h1>
	  <div class="releaseContainer" id="releaseNewForm" style="display: none;">
		<!-- py:for="release in enumerate(releases)" -->
		<form class="burndown show" method="post" id="newReleaseBurndownForm" action="${href.releaseburndown()}" onsubmit="return validate(this);">
			<fieldset>
				<legend>New Release</legend>
				<div style="border-bottom: solid 1px #CCC; margin-bottom: 6px; text-align: right;">
					<a href="javascript:newRelease('close');">[ close ]</a>
				</div>
				<div class="populate">
					<input type="hidden" name="act" value="add"/>
					<span id="release_name_container"><span id="release_name_text"></span>
						Name:		<input name="release_name" label="Name" type="text" maxlength="50" style="width:325px;" required="true"/><br/>
					</span>
					<span id="points_container" style="float: left; margin-right: 10px;"><span id="points_text"></span>
						Points:		<input name="points" type="text" label="Points" maxlength="4" datatype="integer" style="width:25px;" required="true"/>
					</span>
					<span id="velocity_container" style="float: left; margin-right: 10px;"><span id="velocity_text"></span>
						Estimated Velocity: <input name="velocity" label="Velocity" type="text" maxlength="3" datatype="integer" required="true"/>
					</span>
					<span id="init_date_container" style="float: left; margin-right: 10px;"><span id="init_date_text"></span>
						Start date <span style="font-size:9px">(${date_hint})</span>: <input name="init_date" label="Start date" type="text" maxlength="10" style="width:55px" datatype="date" required="true"/>	
					</span>
					<span id="working_days_container" style="float: left; margin-right: 10px;"><span id="working_days_text"></span>
						Working Days per Sprint: <input name="working_days" label="Working Days" value="10" type="text" maxlength="10" datatype="integer" style="width:55px" required="true"/>
					</span>

					<input type="submit" value="OK" py:if="permissions.RELEASE_BURNDOWN_CREATE" style="width:25px;height:20px;font-size:10px;"/>&nbsp;<input type="button" value="Clear" onclick="clearForm(this.form)" style="width:55px;height:20px;font-size:10px;"/>
				</div>
			</fieldset>
		</form>
	  </div>
	  <div style="display: block;" id="releaseNewButton" py:if="permissions.RELEASE_BURNDOWN_CREATE">
		<input type="button" onclick="newRelease('open');" value="New Release" />
	  </div>
	  
	  <form py:for="release in releases" id="release${release.id}" method="post" action="${href.releaseburndown()}" onsubmit="return validate(this);">
			<fieldset>
				<legend>${release['name']}</legend>
				<div class="populate" id="graph${release['id']}">
					<input type="hidden" name="act" value="edit"/>
					<input type="hidden" name="id" value="${release['id']}"/>
					<span id="graphForm${release['id']}" style="display: none;">
						Name:		<input name="release_name" required="true" label="Name" value="${release['name']}" type="text" maxlength="50" style="width:325px;"/>&nbsp;Status:
						<select name="release_status" py:if="release.closed == 0">
							<option value="0" selected="true">open</option>
							<option value="1">closed</option>
						</select>
						<select name="release_status" py:if="release.closed == 1">
							<option value="0">open</option>
							<option value="1" selected="true">closed</option>
						</select>
						<br/>
						Points:		<input name="points" type="text" required="true" label="Points" datatype="integer" value="${release['points']}" maxlength="4" style="width:25px;"/>
						Estimated Velocity: <input name="velocity" required="true" label="Velocity" datatype="integer" value="${release['velocity']}" type="text" maxlength="3"/>
						Start date <span style="font-size:9px">(${date_hint})</span>: <input name="init_date" required="true" label="Start Date" datatype="date" value="${format_date(release['init_date'])}" type="text" maxlength="10" style="width:55px"/>
						Working Days per Sprint: <input name="working_days" required="true" label="Working days" datatype="integer" value="${release['working_days']}" type="text" maxlength="10" style="width:55px"/><br/>
						<input type="submit" value="OK" py:if="permissions.RELEASE_BURNDOWN_MODIFY" style="width:25px;height:20px;font-size:10px;"/>&nbsp;&nbsp;&nbsp;<input type="button" value="REMOVE" py:if="permissions.RELEASE_BURNDOWN_DELETE" onclick="excludeRelease(this.form);" style="width:50px;height:20px;font-size:10px;"/>
						<hr/>
					</span>
					<script py:if="permissions.RELEASE_BURNDOWN_MODIFY">
						jQuery('#graphForm${release.id}').show();
					</script>
					<a href="javascript:Sprint.showResults(${release.id});void(0);" py:if="permissions.RELEASE_BURNDOWN_MODIFY">Edit Sprints</a><br/>
					<table id="sprints${release.id}" cellpadding="3" class="addtask">
						<thead>
							<tr>
								<th>Points</th>
								<th>Added Points</th>
								<th>Removed Points</th>
								<th>End Date</th>
								<th>&nbsp;</th>
							</tr>
						</thead>
						<tbody>
							<tr py:for="sprint in release['sprints']">
								<td><input type="hidden" name="sprint" value="{'due_date': '${format_date(sprint.due_date)}', 'points': ${sprint.points}, 'added_points': ${sprint.added_points}, 'removed_points': ${sprint.removed_points} }"/>${sprint.points}</td>
								<td>${sprint.added_points}</td>
								<td>${sprint.removed_points}</td>
								<td>${format_date(sprint.due_date)}</td>
								<td><a href="javascript:Sprint.edit(document.getElementById('release${release.id}'), {'releaseId': ${release.id}, 'id': ${sprint.id},'due_date': '${format_date(sprint.due_date)}', 'points': ${sprint.points}, 'added_points': ${sprint.added_points}, 'removed_points': ${sprint.removed_points} });void(0);">Edit</a> - <a href="javascript:Sprint.remove(document.getElementById('release${release.id}'), ${sprint.id});void(0);">Remove</a></td>
							</tr>
						</tbody>
						<tfoot>
							<tr>
								<td colspan="5" style="text-align:left">
									<a id="newFormLink${release.id}" href="javascript:Sprint.showForm(document.getElementById('release${release.id}'));void(0)">New Sprint</a><br/>
									<div id="sprintForm${release.id}" style="display: none;">
										<input type="hidden" name="sprint_id"/>
										Done Points: <input name="sprint_points" label="Points" datatype="integer" type="text" maxlength="50" style="width:55px;"/>&nbsp;
										Added Points: <input name="added_points" label="Added Points" datatype="integer" value="0" type="text" maxlength="50" style="width:55px;"/>&nbsp;
										Removed Points: <input name="removed_points" label="Removed Points" datatype="integer" value="0" type="text" maxlength="50" style="width:55px;"/>&nbsp;
										End Date <span style="font-size:9px">(${date_hint})</span>: <input name="due_date" label="Start Date" datatype="date" type="text" maxlength="50" style="width:55px;"/>&nbsp;<br/>
										<input type="button" value="OK" style="width:25px;height:20px;font-size:10px;" onclick="Sprint.save(this.form);"/>
										<input type="button" value="CANCEL" style="width:55px;height:20px;font-size:10px;" onclick="Sprint.cancel(this.form);"/>

									</div>
								</td>
							</tr>
						</tfoot>
					</table>

					<br/>
					<img src="" id="img_release${release.id}" />
					<script>createGraphics(document.forms['release${release.id}'])</script>
				</div>
			</fieldset>
			
			<script type="text/javascript" py:if="release.closed == 1">
				$("#graph${release['id']}").hide();
				$("#graph${release['id']}").after('<a id="graphshow${release.id}" href="javascript:$(\'#graph${release.id}\').show();$(\'#graphshow${release.id}\').hide();void(0);">The release is completed, the chart shows this release.</a>');
			</script>
	  </form>
	  <br/>
	  <a href="javascript:window.open('${href.releaseburndown()}?act=view_audit', 'auditWindow', 'scrollbars = yes, width=640, height=400');void(0);" py:if="permissions.RELEASE_BURNDOWN_ADMIN">View audit log</a>
    </div>
  </body>
</html>